/* 7-bit I2C slave addresses:
 *  0x23 (ADDR pin low)
 *  0x5C (ADDR pin high)
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/ioctl.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_gpio.h>


#define WRADDR  0x46
#define RDADDR  0x47

#define PWON      0x01
#define CH_RM    0x10 //Continuously H-Resolution Mode
#define OTH_RM	 0x20 //One Time H-Resolution Mode

struct i2c_client *bh1750_client;

static int i2c_read_byte(struct i2c_client * client, uint8_t reg, uint8_t * buf, int len)
{
	struct i2c_msg msgs[2];

    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = &reg;

    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = len;
    msgs[1].buf = buf;

    if(i2c_transfer(client->adapter, msgs, 2) != 2)
    	return 0;
    return 1;
}

static int i2c_write_byte(struct i2c_client * client, uint8_t reg, uint8_t buf)
{
	struct i2c_msg msgs[2];

	msgs[0].addr = client->addr;
	msgs[0].flags = 0;
	msgs[0].len = 1;
	msgs[0].buf = &reg;
	
	msgs[1].addr = client->addr;
	msgs[1].flags = 0;
	msgs[1].len = 1;
	msgs[1].buf = &buf;

    if(i2c_transfer(client->adapter, msgs, 2) != 2)
    	return 0;
    return 1;
}


static ssize_t rk3568_light_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
 	int ret;
 	char data_buf[4];
	short value;
	
	memset(data_buf, 0, sizeof(data_buf));
	memset(&value, 0, sizeof(value));
	//printk("<0>""sizeof(data_buf) = %d\nsizeof(light() = %d\n",sizeof(data_buf),sizeof(value));
	

	ret = i2c_write_byte(bh1750_client,RDADDR,PWON);
	if(ret ==0 )
	{
		printk("PWON i2c_write_byte error\r\n");
	}
	
	ret = i2c_write_byte(bh1750_client,RDADDR,CH_RM);
	if(ret ==0 )
	{
		printk("CH_RM i2c_write_byte error\r\n");
	}
	msleep(250);
	
	ret = i2c_read_byte(bh1750_client,RDADDR,data_buf,2);
	if(ret != 1){
		printk("%s %d i2c read byte data err\n",__FUNCTION__,__LINE__);
		return -1;
	}
	
	value = (data_buf[0]<<8) | (data_buf[1]<<0);
	//printk("value = %d\n",value);
	
	
	
	ret = copy_to_user(buf, &value, sizeof(value));
	if(ret < 0){
		printk("%s %d err copy light value to user\n",__FUNCTION__,__LINE__);
		return -EFAULT;
	}
	return ret;
}

static const struct file_operations rk3568_light_fops = {
	.owner = THIS_MODULE,
	.read = rk3568_light_read,
};


static struct miscdevice rk3568_bh1750_misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "light_drv",
	.fops = &rk3568_light_fops,
};


static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret;
	// struct device_node *bh1750_node = NULL; 
	bh1750_client = client;
	
	printk("The match successful!\n");
	
	printk("client->addr = %x\n",client->addr);
	ret = misc_register(&rk3568_bh1750_misc);   //×￠2á×?·?éè±?
	if(ret < 0){
		printk("misc register error\n");
		goto err_register_error;		
	}
	

	printk("bh1750 dirve install succee\n");
	return 0;
	
err_register_error:
	return 0;
}


static int i2c_remove(struct i2c_client *client)
{	
	misc_deregister(&rk3568_bh1750_misc);
	
	printk("rk3568_bh1750_exit\n");	
	return 0;
}


static const struct i2c_device_id i2c_id[] = {
	{ "bh1750", 0 },
	{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(i2c, i2c_id);


static struct of_device_id i2c_match[] = {
	{.compatible = "rohm,bh1750", },
	{ }
};

MODULE_DEVICE_TABLE(of, i2c_match);


static struct i2c_driver i2c_driver = {
	.driver = {
		.name = "bh1750",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(i2c_match),
	},
	.probe = i2c_probe,
	.remove = i2c_remove,
	.id_table = i2c_id,	
};

module_i2c_driver(i2c_driver);

MODULE_AUTHOR("GEC");
MODULE_DESCRIPTION("BH1750 als driver");
MODULE_LICENSE("GPL v2");



